/*
 * 文件名： DataDecoder.java
 * 
 * 创建日期： 2016年12月13日
 *
 * Copyright(C) 2016, by <a href="mailto:liws@xingyuanauto.com">liws</a>.
 *
 * 原始作者: liws
 *
 */
package com.moli.iov.protocol.codec;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.moli.iov.protocol.enums.DateTimeTag;
import com.moli.iov.protocol.enums.IDictsEnumTag;
import com.moli.iov.protocol.enums.IDictsMultiEnumTag;
import com.moli.iov.protocol.model.realtime.RealTimeInfoReq;
import com.moli.iov.protocol.util.UnsignedNumberUtil;
import com.moli.iov.util.ByteArrayUtil;
import com.moli.iov.util.NumberUtil;


/**
 * 协议解析器
 *
 * @author <a href="mailto:liws@xingyuanauto.com">liws</a>
 * @version $Revision$
 * @param <instance>
 * @since 2016年12月13日
 */
public class DataDecoder<T> {

    // 缓存对象字段和方法合集信息
    private static final Map<Class<?>, List<Object>> fieldsAndMethodsCache = new HashMap<Class<?>, List<Object>>();

    // 缓存对象字段信息
    private static final Map<Class<?>, List<Field>> fieldsCache = new HashMap<Class<?>, List<Field>>();

    // 缓存对象set方法信息
    private static final Map<Class<?>, List<Method>> setMethodsCache = new HashMap<Class<?>, List<Method>>();

    // 缓存Class 与 注解对象 对应关系
    private static final Map<Class<?>, Serialize> classesSerializeCache = new HashMap<Class<?>, Serialize>();

    // 缓存 字段和方法 与 注解对象 对应关系
    private static final Map<Object, Serialize> fieldAndMethodsSerializeCache = new HashMap<Object, Serialize>();

    // 缓存method 与 注解对象 对应关系
    private static final Map<Method, Serialize> methodsSerializeCache = new HashMap<Method, Serialize>();

    // 缓存field 与 注解对象 对应关系
    private static final Map<Field, Serialize> fieldssSerializeCache = new HashMap<Field, Serialize>();

    // 缓存method 与 参数类型数组 对应关系
    private static final Map<Method, Class<?>[]> methodsParameterTypes = new HashMap<Method, Class<?>[]>();

    // 缓存字段类型 与 IDictsEnumTag 实现 对应关系
    private static final Map<Class, IDictsEnumTag> fieldssEnumCache = new HashMap<Class, IDictsEnumTag>();

    // 缓存字段类型 与 IDictsEnumTag 实现 对应关系
    private static final Map<Class, IDictsMultiEnumTag> fieldssMultiEnumCache = new HashMap<Class, IDictsMultiEnumTag>();

//    private T instance;

//    private boolean isBigEndian = true;

//    private byte[] bytes;

//    private boolean containSuper = true;

    public DataDecoder() {
    }

//    public DataDecoder<T> containSuper(boolean value) {
//        this.containSuper = value;
//        return this;
//    }

    public void decode(T instance, byte[] bytes) throws Exception {
    	decode(instance,bytes,true);
    }
    /**
     * 由byte数组转为对象
     */
    public void decode(T instance, byte[] bytes,boolean containSuper) throws Exception {
//        this.instance = instance;
//        this.bytes = bytes;
        Class<?> clazz = instance.getClass();
        Serialize serClass = null;
        if ((serClass = classesSerializeCache.get(clazz)) == null) {
            if (clazz.isAnnotationPresent(Serialize.class)) {
                serClass = (Serialize) clazz.getAnnotation(Serialize.class);
                classesSerializeCache.put(clazz, serClass);
            } else {
                return;
            }
        }
        
        // 字段信息
        List<Field> fields;
        if ((fields = fieldsCache.get(clazz)) == null) {
            if (containSuper)
                fields = Arrays.asList(clazz.getFields());
            else
                fields = Arrays.asList(clazz.getDeclaredFields());
            // 对field进行过滤操作
            List<Field> filterFields = new ArrayList<Field>();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Serialize.class)) {
                    field.setAccessible(true);
                    filterFields.add(field);
                }
            }
            fields = filterFields;
            fieldsCache.put(clazz, filterFields);
        }
        // 解析字段
        for (Field field : fields) {
            setFieldValue(serClass, field, instance, bytes);
        }
        // 方法信息
        List<Method> methods = null;
        if ((methods = setMethodsCache.get(clazz)) == null) {
            if (containSuper)
                methods = Arrays.asList(clazz.getMethods());
            else
                methods = Arrays.asList(clazz.getDeclaredMethods());
            // 对field进行过滤操作
            List<Method> filterMethods = new ArrayList<Method>();
            for (Method method : methods) {
                if (isSetter(method) && method.isAnnotationPresent(Serialize.class)) {
                    method.setAccessible(true);
                    filterMethods.add(method);
                }
            }
            methods = filterMethods;
            setMethodsCache.put(clazz, filterMethods);
        }
        // 解析方法
        for (Method method : methods) {
            setMethodValue(serClass, method,instance, bytes);
        }
    }

    /**
     * @param serClass
     * @param method
     */
    private void setMethodValue(Serialize serClass, Method method,T instance,byte[] bytes)
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, Exception {
        Serialize serMethod = null;
        if ((serMethod = methodsSerializeCache.get(method)) == null) {
            serMethod = method.getAnnotation(Serialize.class);
            methodsSerializeCache.put(method, serMethod);
        }
        Object value = null;
        Class<?>[] types = null;
        if ((types = methodsParameterTypes.get(method)) == null) {
            types = method.getParameterTypes();
            methodsParameterTypes.put(method, types);
        }
        if (types.length != 1)
            return;
        if ("byte".equals(serClass.unit().toLowerCase(Locale.CHINA))) {
            value = parseValue(bytes, serClass.sign(), serMethod, types[0]);
        }
        if (value != null)
            method.invoke(instance, value);
    }

    /**
     * @param serClass
     * @param field
     */
    private void setFieldValue(Serialize serClass, Field field,T instance,byte[] bytes)
            throws IllegalArgumentException, IllegalAccessException, Exception {
        Serialize serField = null;
        if ((serField = fieldssSerializeCache.get(field)) == null) {
            serField = (Serialize) field.getAnnotation(Serialize.class);
            fieldssSerializeCache.put(field, serField);
        }
        Object value = null;
        if ("byte".equals(serClass.unit().toLowerCase(Locale.CHINA))) {
            value = parseValue(bytes, serClass.sign(), serField, field.getType());
        }
        setFieldValue(instance,field, value);
    }

    private void setFieldValue(T instance,Field field, Object value) throws IllegalArgumentException, IllegalAccessException {

        // long offset =
        // UnSafeSupport.getInstance().objectFieldOffset(field);

        if (value instanceof Boolean) {
            // UnSafeSupport.getInstance().putBoolean(instance, offset,
            // (Boolean) value);
            field.setBoolean(instance, (Boolean) value);
        } else if (value instanceof Byte) {
            // UnSafeSupport.getInstance().putByte(instance, offset, (Byte)
            // value);
            field.setByte(instance, (Byte) value);
        } else if (value instanceof Character) {
            // UnSafeSupport.getInstance().putChar(instance, offset,
            // (Character) value);
            field.setChar(instance, (Character) value);
        } else if (value instanceof Double) {
            // UnSafeSupport.getInstance().putDouble(instance, offset,
            // (Double) value);
            field.setDouble(instance, (Double) value);
        } else if (value instanceof Float) {
            // UnSafeSupport.getInstance().putDouble(instance, offset,
            // (Float) value);
            field.setFloat(instance, (Float) value);
        } else if (value instanceof Integer) {
            // UnSafeSupport.getInstance().putInt(instance, offset,
            // (Integer) value);
            field.setInt(instance, (Integer) value);
        } else if (value instanceof Long) {
            // UnSafeSupport.getInstance().putLong(instance, offset, (Long)
            // value);
            field.setLong(instance, (Long) value);
        } else if (value instanceof Short) {
            // UnSafeSupport.getInstance().putShort(instance, offset,
            // (Short) value);
            field.setShort(instance, (Short) value);
        } else if (value != null) {
            // UnSafeSupport.getInstance().putObject(instance, offset,
            // value);
            field.set(instance, value);
        }
    }

    private Object parseValue(byte[] bytes, int sign, Serialize serInfo, Class<?> clazz)
            throws InstantiationException, IllegalAccessException, SecurityException, IllegalArgumentException {
        if (serInfo.isBigEndian()) {
            return parseValue_BigEndian(bytes, sign, serInfo, clazz);
        } else {
            return parseValue_Little(bytes, sign, serInfo, clazz);
        }
    }

    /**
     * 判断byte[]是否全为ff或fe或正常值 处理ff或fe报文，by liweisong
     * 
     * @param tBytes
     * @return 1：ff，2：fe，0：正常
     */
    private static int effectValue(byte[] tBytes) {
        int len = tBytes.length;
        int flag = 0;
        // 计算最大值
        int max = tBytes[0] & 0xFF;
        for (int i = 1; i < len; i++) {
            int val = tBytes[i] & 0xFF;
            if (val > max) {
                max = val;
            }
        }
        // 计算最小值
        int min = tBytes[0] & 0xFF;
        for (int j = 0; j < len; j++) {
            int val = tBytes[j] & 0xFF;
            if (val < min) {
                min = val;
            }
        }
        if (max == min && max == 255) {// 判断是否全是ff，返回无效
            flag = 1;
        } else if ((max == 255 && min == 254) || (max == min && max == 254)) {// 判断是否全是fe，返回异常
            flag = 2;
        } else {
            flag = 0;
        }
        return flag;
    }

    public static void main(String[] args) {
    	byte[] tBytes = new byte[] {(byte) 0xff, (byte) 0xfe, (byte) 0xff };
        RealTimeInfoReq realTimeInfoReq = new RealTimeInfoReq();
        DataDecoder<RealTimeInfoReq> decoder = new DataDecoder<>();
        try {
            int flag = decoder.effectValue(tBytes);
            System.out.println(flag);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    /**
     * 将byte数组转为对应的对象
     * 
     * @param bytes
     *            byte数组
     * @param sign
     *            是否有符号
     * @param serInfo
     *            序列化方式
     * @param clazz
     *            目标对象
     * @return
     */
    private Object parseValue_BigEndian(byte[] bytes, int pSign, Serialize serInfo, Class<?> fieldClassType)
            throws InstantiationException, IllegalAccessException, SecurityException, IllegalArgumentException {
        int offset = serInfo.offset();
        boolean sign = true;
        if (pSign == -1)
            pSign = serInfo.sign();
        sign = pSign == 0 ? false : true;
        int len = serInfo.size();
        double min = serInfo.min();
        double max = serInfo.max();
        double exception = serInfo.exception();// 异常值
        double invalid = serInfo.invalid();// 无效值
        double coefficient = serInfo.coefficient();
        double increment = serInfo.valOffset();
        int precision = serInfo.precision();
        int parseSize = serInfo.parseSize();
        if (bytes.length < offset && len == -1)
            return null;
        if (bytes.length < offset + len)
            return null;
        if (len == -1)
            len = bytes.length - offset;
        /**
         * 修改上报ff与fe对应的值，by liweisong
         */
        if (Byte.class.isAssignableFrom(fieldClassType) || byte.class.isAssignableFrom(fieldClassType)) {
            double value = sign ? bytes[offset] : bytes[offset] & 0xFF;
            if (value == 254) {
                value = exception;
            }else if (value == 255) {
                value = invalid;
            }else{
                value = value * coefficient - increment;
            }
            return (byte) value;
        } else if (Byte[].class.isAssignableFrom(fieldClassType) || byte[].class.isAssignableFrom(fieldClassType)) {
            byte[] value = new byte[len];
            System.arraycopy(bytes, offset, value, 0, len);
            return value;
        } else if (Short.class.isAssignableFrom(fieldClassType) || short.class.isAssignableFrom(fieldClassType)) {
            short result;
            byte[] evalue = new byte[len];
            System.arraycopy(bytes, offset, evalue, 0, len);
            int flag = effectValue(evalue);
            if (flag == 1) {
                result = (short) invalid;
            } else if (flag == 2) {
                result = (short) exception;
            } else {
                short value = ByteArrayUtil.toShort(bytes, offset, len);
                result = sign ? value : NumberUtil.toShort(signChange(value, Short.class));
                result = (short) (result * (coefficient) - increment);
            }
            return result;
        } else if (Integer.class.isAssignableFrom(fieldClassType) || int.class.isAssignableFrom(fieldClassType)) {
            int result;
            byte[] evalue = new byte[len];
            System.arraycopy(bytes, offset, evalue, 0, len);
            int flag = effectValue(evalue);
            if (flag == 1) {
                result = (int) invalid;
            } else if (flag == 2) {
                result = (int) exception;
            } else {
                int value = ByteArrayUtil.toInt(bytes, offset, len);
                result = sign ? value : NumberUtil.toInteger(signChange(value, Integer.class));
                result = ((Double) (result * coefficient - increment)).intValue();
            }
            return result;
        } else if (Long.class.isAssignableFrom(fieldClassType) || long.class.isAssignableFrom(fieldClassType)) {
            long result;
            byte[] evalue = new byte[len];
            System.arraycopy(bytes, offset, evalue, 0, len);
            int flag = effectValue(evalue);
            if (flag == 1) {
                result = (long) invalid;
            } else if (flag == 2) {
                result = (long) exception;
            } else {
                long value = ByteArrayUtil.toLong(bytes, offset, len);
                result = sign ? value : NumberUtil.toLong(signChange(value, Long.class));
                result = ((Double) (result * coefficient - increment)).longValue();
            }
            return result;
        } else if (Float.class.isAssignableFrom(fieldClassType) || float.class.isAssignableFrom(fieldClassType)) {
            float result = 0.0f;
            byte[] evalue = new byte[len];
            System.arraycopy(bytes, offset, evalue, 0, len);
            int flag = effectValue(evalue);
            if (flag == 1) {
                result = (float) invalid;
            } else if (flag == 2) {
                result = (float) exception;
            } else {
                Object value;
                if (len == 0)
                    value = 0;
                else if (len <= 1) {
                    value = bytes[offset];
                    result = sign ? NumberUtil.toByte(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (len <= 2) {
                    value = ByteArrayUtil.toShort(bytes, offset, len);
                    result = sign ? NumberUtil.toShort(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (len <= 4) {
                    value = ByteArrayUtil.toInt(bytes, offset, len);
                    result = sign ? NumberUtil.toInteger(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (len <= 8) {
                    value = ByteArrayUtil.toLong(bytes, offset, len);
                    result = sign ? NumberUtil.toLong(value) : NumberUtil.toLong(signChange(value, Long.class));
                }
                result = ((Double) (result * coefficient - increment)).floatValue();
            }
            return result;
        } else if (Double.class.isAssignableFrom(fieldClassType) || double.class.isAssignableFrom(fieldClassType)) {
            double result = 0;
            byte[] evalue = new byte[len];
            System.arraycopy(bytes, offset, evalue, 0, len);
            int flag = effectValue(evalue);
            if (flag == 1) {
                result = (double) invalid;
            } else if (flag == 2) {
                result = (double) exception;
            } else {
                Object value = null;
                if (parseSize == -1) {
                    parseSize = len;
                }
                if (parseSize == 0)
                    value = 0;
                else if (parseSize <= 1) {
                    value = bytes[offset];
                    result = sign ? NumberUtil.toByte(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (parseSize <= 2) {
                    value = ByteArrayUtil.toShort(bytes, offset, len);
                    result = sign ? NumberUtil.toShort(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (parseSize <= 4) {
                    value = ByteArrayUtil.toInt(bytes, offset, len);
                    result = sign ? NumberUtil.toInteger(value) : NumberUtil.toLong(signChange(value, Long.class));
                } else if (parseSize <= 8) {
                    value = ByteArrayUtil.toLong(bytes, offset, len);
                    result = sign ? NumberUtil.toLong(value) : NumberUtil.toLong(signChange(value, Long.class));
                }
                result = ((Double) (result * coefficient - increment));
                BigDecimal b = new BigDecimal(result);
                result = b.setScale(precision, BigDecimal.ROUND_HALF_UP).doubleValue();
            }
            return result;
        } else if (Date.class.isAssignableFrom(fieldClassType)) {
            long l;
            if (len <= 4)
                l = ByteArrayUtil.toLong(bytes, offset, len) * 1000;
            else
                l = ByteArrayUtil.toLong(bytes, offset, len);
            return new Date(l);
        } else if (DateTimeTag.class.isAssignableFrom(fieldClassType)) {
            byte[] value = new byte[len];
            System.arraycopy(bytes, offset, value, 0, len);
            return DateTimeTag.valueOf(value);
        } else if (String.class.isAssignableFrom(fieldClassType)) {
            String result = "";
            byte[] strBytes = new byte[len];
            System.arraycopy(bytes, offset, strBytes, 0, len);
            int flag = effectValue(strBytes);
            if (flag == 1) {
                result = String.valueOf(invalid);
            } else if (flag == 2) {
                result = String.valueOf(exception);
            } else {
                result = ByteArrayUtil.asciiToStr(strBytes);
            }
            return result;
        } else if (IDictsEnumTag.class.isAssignableFrom(fieldClassType)) {
            byte tByte = bytes[offset];
            Object object;
            if (fieldClassType.isEnum()) {
                IDictsEnumTag enumObj = null;
                if (fieldssEnumCache.get(fieldClassType) == null) {
                    IDictsEnumTag[] classes = (IDictsEnumTag[]) fieldClassType.getEnumConstants();
                    if (classes.length > 0) {
                        enumObj = classes[0];
                        fieldssEnumCache.put(fieldClassType, enumObj);
                    }
                } else {
                    enumObj = fieldssEnumCache.get(fieldClassType);
                }
                object = enumObj.valueOf(tByte);
            } else {
                object = ((IDictsEnumTag) fieldClassType.newInstance()).valueOf(tByte);
            }
            return object;

        } else if (IDictsMultiEnumTag.class.isAssignableFrom(fieldClassType)) {
            byte[] tByte = new byte[len];
            System.arraycopy(bytes, offset, tByte, 0, len);
            Object object = null;
            if (fieldClassType.isEnum()) {
                IDictsMultiEnumTag enumObj = null;
                if (fieldssMultiEnumCache.get(fieldClassType) == null) {
                    IDictsMultiEnumTag[] classes = (IDictsMultiEnumTag[]) fieldClassType.getEnumConstants();
                    if (classes.length > 0) {
                        enumObj = classes[0];
                        fieldssMultiEnumCache.put(fieldClassType, enumObj);
                    }
                } else {
                    enumObj = fieldssMultiEnumCache.get(fieldClassType);
                }
                object = enumObj.valueOf(tByte);
            } else {
                object = ((IDictsMultiEnumTag) fieldClassType.newInstance()).valueOf(tByte);
            }
            return object;

        }
        return null;
    }

    /**
     * 将byte数组转为对应的对象
     * 
     * @param bytes
     *            byte数组
     * @param sign
     *            是否有符号
     * @param serInfo
     *            序列化方式
     * @param clazz
     *            目标对象
     * @return
     */
    private Object parseValue_Little(byte[] bytes, int pSign, Serialize serInfo, Class<?> clazz) {
        int offset = serInfo.offset();
        boolean sign = true;
        if (pSign == -1)
            pSign = serInfo.sign();
        sign = pSign == 0 ? false : true;
        int len = serInfo.size();
        double min = serInfo.min();
        double max = serInfo.max();
        double coefficient = serInfo.coefficient();
        double increment = serInfo.valOffset();
        if (bytes.length < offset + len)
            return null;
        if (len == -1)
            len = bytes.length - offset;
        if (Byte.class.isAssignableFrom(clazz) || byte.class.isAssignableFrom(clazz)) {
            double value = sign ? bytes[offset] : bytes[offset] & 0xFF;

            if (value > max)
                value = max;
            if (value < min)
                value = min;
            value = value * coefficient - increment;
            return (byte) value;
        } else if (Byte[].class.isAssignableFrom(clazz) || byte[].class.isAssignableFrom(clazz)) {
            byte[] value = new byte[len];
            System.arraycopy(bytes, offset, value, 0, len);
            return value;
        } else if (Short.class.isAssignableFrom(clazz) || short.class.isAssignableFrom(clazz)) {
            short result = 0;
            short value = ByteArrayUtil.littleToShort(bytes, offset, len);
            result = sign ? result : NumberUtil.toShort(signChange(value, Short.class));
            if (result > max)
                result = (short) max;
            if (result < min)
                result = (short) min;
            result = ((Double) (result * coefficient - increment)).shortValue();
            return result;
        } else if (Integer.class.isAssignableFrom(clazz) || int.class.isAssignableFrom(clazz)) {
            int result = 0;
            int value = result = ByteArrayUtil.littleToInt(bytes, offset, len);
            result = sign ? result : NumberUtil.toInteger(signChange(value, Integer.class));
            if (result > max)
                result = (int) max;
            if (result < min)
                result = (int) min;
            result = ((Double) (result * coefficient - increment)).intValue();
            return result;
        } else if (Long.class.isAssignableFrom(clazz) || long.class.isAssignableFrom(clazz)) {
            long result = 0;
            long value = result = ByteArrayUtil.littleToLong(bytes, offset, len);
            result = sign ? result : NumberUtil.toLong(signChange(value, Long.class));

            if (result > max)
                result = (long) max;
            if (result < min)
                result = (long) min;
            result = ((Double) (result * coefficient - increment)).longValue();
            return result;

        } else if (Float.class.isAssignableFrom(clazz) || float.class.isAssignableFrom(clazz)) {
            float result = 0;
            if (len == 0)
                result = 0;
            else if (len <= 1) {
                byte b = bytes[offset];
                result = sign ? b : b & 0xFF;
            } else if (len <= 2) {
                short s = ByteArrayUtil.littleToShort(bytes, offset, len);
                result = sign ? s : s & 0xFFFF;
            } else if (len <= 4) {
                int i = ByteArrayUtil.littleToInt(bytes, offset, len);
                result = sign ? i : i & 0xFFFFFFFF;
            } else if (len <= 8) {
                long l = ByteArrayUtil.littleToLong(bytes, offset, len);
                result = sign ? l : l & 0xFFFFFFFF;
            }

            if (result > max)
                result = (float) max;
            if (result < min)
                result = (float) min;
            result = ((Double) (result * coefficient - increment)).floatValue();
            return result;
        } else if (Double.class.isAssignableFrom(clazz) || double.class.isAssignableFrom(clazz)) {
            double result = 0;
            if (len == 0)
                result = 0;
            else if (len <= 1) {
                byte b = bytes[offset];
                result = sign ? b : b & 0xFF;
            } else if (len <= 2) {
                short s = ByteArrayUtil.littleToShort(bytes, offset, len);
                result = sign ? s : s & 0xFFFF;
            } else if (len <= 4) {
                int i = ByteArrayUtil.littleToInt(bytes, offset, len);
                result = sign ? i : i & 0xFFFFFFFF;
            } else if (len <= 8) {
                long l = ByteArrayUtil.littleToLong(bytes, offset, len);
                result = sign ? l : l & 0xFFFFFFFF;
            }

            if (result > max)
                result = max;
            if (result < min)
                result = min;
            result = result * coefficient - increment;
            return result;
        } else if (Date.class.isAssignableFrom(clazz)) {
            long l;
            if (len <= 4)
                l = ByteArrayUtil.littleToLong(bytes, offset, len) * 1000;
            else
                l = ByteArrayUtil.littleToLong(bytes, offset, len);
            return new Date(l);
        } else if (String.class.isAssignableFrom(clazz)) {
            byte[] strBytes = new byte[len];
            System.arraycopy(bytes, offset, strBytes, 0, len);
            return ByteArrayUtil.asciiToStr(strBytes);
        }
        return null;
    }

    /**
     * 有无符号类型转换
     * 
     * @param data
     *            原始数据
     * @param target
     *            目标类型
     * @return
     */
    private Object signChange(Object data, Class<?> target) {
        if (data instanceof Byte) {
            byte tByte = NumberUtil.toByte(data);
            if (Byte.class.isAssignableFrom(target)) {
                return (byte) (tByte & 0xFF);
            } else if (Short.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedByteValue(tByte);
            } else if (Integer.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedShortValue((short) (tByte));
            } else if (Long.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedIntValue((int) (tByte));
            }
        } else if (data instanceof Short) {
            short tShort = NumberUtil.toShort(data);
            if (Byte.class.isAssignableFrom(target)) {
                return (byte) (tShort & 0xFFFF);
            } else if (Short.class.isAssignableFrom(target)) {
                return (short) (tShort & 0xFFFF);
            } else if (Integer.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedShortValue(tShort);
            } else if (Long.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedIntValue((int) (tShort));
            }
        } else if (data instanceof Integer) {
            int tInt = NumberUtil.toInteger(data);
            if (Byte.class.isAssignableFrom(target)) {
                return (byte) (tInt & 0xFFFFFF);
            } else if (Short.class.isAssignableFrom(target)) {
                return (short) (tInt & 0xFFFFFF);
            } else if (Integer.class.isAssignableFrom(target)) {
                return tInt & 0xFFFFFF;
            } else if (Long.class.isAssignableFrom(target)) {
                return UnsignedNumberUtil.toUnsignedIntValue(tInt);
            }

        } else if (data instanceof Long) {
            long tLong = NumberUtil.toLong(data);
            if (Byte.class.isAssignableFrom(target)) {
                return (byte) (tLong & 0xFFFFFFFF);
            } else if (Short.class.isAssignableFrom(target)) {
                return (short) (tLong & 0xFFFFFFFF);
            } else if (Integer.class.isAssignableFrom(target)) {
                return (int) (tLong & 0xFFFFFFFF);
            } else if (Long.class.isAssignableFrom(target)) {
                BigInteger bigInteger = UnsignedNumberUtil.toUnsignedLongValue(tLong);
                return bigInteger.longValue();
            }
        }
        return data;
    }

    private static boolean isSetter(Method method) {
        if (!method.getName().startsWith("set"))
            return false;
        if (method.getParameterTypes().length != 1)
            return false;
        return true;
    }
}
